package cytargetlinker.conversion;

import java.io.File;
import java.io.PrintWriter;
import java.util.List;
import java.util.logging.Logger;

import uk.co.flamingpenguin.jewel.cli.ArgumentValidationException;
import uk.co.flamingpenguin.jewel.cli.CliFactory;
import uk.co.flamingpenguin.jewel.cli.Option;
import cytargetlinker.conversion.graph.GmlWriter;
import cytargetlinker.conversion.graph.Graph;
import cytargetlinker.conversion.graph.XGMMLWriter;

/**
 * Commonly used command line arguments to be parsed.
 * @author Thomas
 */
public class ArgsParser {
	private final static Logger log = Logger.getLogger(ArgsParser.class.getName());
	
	public static <A> A parse(String[] args, Class<? extends A> c) throws ArgumentValidationException {
		return CliFactory.parseArguments(c, args);
	}

	public interface AHelp {
		@Option(helpRequest = true, shortName = "h")
		boolean getHelp();
	}
	
	public interface AFilesIn {
		@Option(shortName = "i", description = "The path(s) to the input file(s).")
		public List<File> getInput();
	}
	
	public interface AFilesOut {
		@Option(shortName = "o", description = "The output GML file or directory to write the network(s) to.")
		public File getOutput();
		public boolean isOutput();
		
		@Option(shortName = "t", description = "The file type to write (gml or xgmml).")
		public String getType();
		public boolean isType();
	}

	public interface AFilesAttributes {
		@Option(shortName = "n", description = "The name of the network.")
		public String getName();
		public boolean isName();
		
		@Option(shortName = "a", description = "Annotation file")
		public String getAnnotationFile();
		public boolean isAnnotationFile();
		
		@Option(longName = "bridgeDbSource", description = "BridgeDb mapping file for the source nodes")
		public String getBridgeDbFileSource();
		public boolean isBridgeDbFileSource();
		
		@Option(longName = "bridgeDbTarget", description = "BridgeDb mapping file for the target nodes")
		public String getBridgeDbFileTarget();
		public boolean isBridgeDbFileTarget();
		
		@Option(longName = "organism", description = "BridgeDb mapping file")
		public String getOrganism();
		public boolean isOrganism();
		
		@Option(shortName = "s", description = "TFe sources (auto or user)")
		public String getSource();
		public boolean isSource();
	}
	
	public interface AIDMapper {
		@Option(description = "Bridgedb connection strings to idmappers to use to translate between xrefs of different types.")
		public List<String> getIdm();
		public boolean isIdm();
		
		@Option(defaultValue = { "L", "Ce" }, description = "The datasource(s) to translate all xrefs to (use system code).")
		public List<String> getDs();
	}
	
	public interface GraphBuilder {
		public Graph buildGraph(File in) throws Exception;
	}
	
	private interface GraphWriter {
		public void write(Graph g, PrintWriter out) throws Exception;
	}
	
	private static class XGMML implements GraphWriter {
		public void write(Graph g, PrintWriter out) throws Exception { XGMMLWriter.write(g, out); }
	}
	
	private static class GML implements GraphWriter {
		public void write(Graph g, PrintWriter out) throws Exception { GmlWriter.write(g, out); }
	}
	
	public static void convertAndWrite(AFilesIn fi, AFilesOut fo, GraphBuilder gb) throws Exception {
		String type = "xgmml";
		if(fo.isType()) type = fo.getType();

		GraphWriter writer = new XGMML();
		if("xgmml".equals(type)) {
			
		} else if("gml".equals(type)) {
			writer = new GML();
		} else {
			log.severe("Unsupported file type " + type + "\n");
		}
		
		if(fi == null || fi.getInput().size() == 1) {
			File input = fi == null ? null : fi.getInput().get(0);
			
			File output = fo.isOutput() ? fo.getOutput() : 
				new File(fi.getInput().get(0).getAbsolutePath() + "." + type);
			log.info("Converting " + input + " to " + output + "\n");
			Graph g = gb.buildGraph(input);
			PrintWriter po = new PrintWriter(output);
			writer.write(g, po);
			po.close();
		} else {
			for(File i : fi.getInput()) {
				File output = fo.isOutput() ? fo.getOutput() : new File(i.getParent());
				output.mkdirs();
				log.info("Converting " + i + " to " + output + "\n");
				Graph g = gb.buildGraph(i);
				PrintWriter po = new PrintWriter(output);
				writer.write(g, po);
				po.close();
			}
		}
	}
}
